/**
* @file The following macros are for defining c stubs of ocaml functions
*
*
* @author gdhuang@ntu.edu.tw
*/

#ifndef _OCAML_STUB_H_
#define _OCAML_STUB_H_

#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/callback.h>


#define DECLARE_STUB_1(ocamlfn, cfn, arg1) \
	value cfn(value arg1);
#define DEFINE_STUB_1(ocamlfn, cfn, arg1)	\
  inline value cfn(value arg1) { \
    static value* cfn##_closure=NULL; \
    if(cfn##_closure==NULL) \
      cfn##_closure = caml_named_value(#ocamlfn); \
    return caml_callback(*cfn##_closure, arg1); \
} 

#define DECLARE_STUB_2(ocamlfn, cfn, arg1, arg2) \
  value cfn(value arg1, value arg2);
#define DEFINE_STUB_2(ocamlfn, cfn, arg1, arg2)	\
  inline value cfn(value arg1, value arg2) { \
    static value* cfn##_closure=NULL; \
    if(cfn##_closure==NULL) \
      cfn##_closure = caml_named_value(#ocamlfn); \
    return caml_callback2(*cfn##_closure, arg1, arg2); \
} 

#define DECLARE_STUB_3(ocamlfn, cfn, arg1, arg2, arg3) \
  value cfn(value arg1, value arg2, value arg3);
#define DEFINE_STUB_3(ocamlfn, cfn, arg1, arg2, arg3)	\
  inline value cfn(value arg1, value arg2, value arg3) { \
    static value* cfn##_closure=NULL; \
    if(cfn##_closure==NULL) \
      cfn##_closure = caml_named_value(#ocamlfn); \
    return caml_callback3(*cfn##_closure, arg1, arg2, arg3); \
} 

#define DECLARE_STUB_4(ocamlfn, cfn, arg1, arg2, arg3, arg4) \
  value cfn(value arg1, value arg2, value arg3, value arg4);
#define DEFINE_STUB_4(ocamlfn, cfn, arg1, arg2, arg3, arg4)	\
  inline value cfn(value arg1, value arg2, value arg3, value arg4) { \
    static value* cfn##_closure=NULL; \
    value args[4] = {arg1, arg2, arg3, arg4}; \
    if(cfn##_closure==NULL) \
      cfn##_closure = caml_named_value(#ocamlfn); \
    return caml_callbackN(*cfn##_closure, 4, args); \
} 

#define DECLARE_STUB_5(ocamlfn, cfn, arg1, arg2, arg3, arg4, arg5) \
  value cfn(value arg1, value arg2, value arg3, value arg4, value arg5);
#define DEFINE_STUB_5(ocamlfn, cfn, arg1, arg2, arg3, arg4, arg5)	\
  inline value cfn(value arg1, value arg2, value arg3, value arg4, value arg5) { \
    static value* cfn##_closure=NULL; \
    value args[5] = {arg1, arg2, arg3, arg4, arg5}; \
    if(cfn##_closure==NULL) \
      cfn##_closure = caml_named_value(#ocamlfn); \
    return caml_callbackN(*cfn##_closure, 5, args); \
} 

#define DECLARE_STUB_N(ocamlfn, cfn, n, args)	\
  value cfn(int n, value* args);
#define DEFINE_STUB_N(ocamlfn, cfn, n, args)	\
  inline value cfn(int n, value* args) { \
    static value *cfn##_closure = NULL; \
    if(cfn##_closure==NULL) \
      cfn##_closure = caml_named_value(#ocamlfn); \
    return caml_callbackN(*cfn##_closure, n, args); \
} 



#endif
